#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "BehavioralFeature.h"
#include "ParameterableElement.h"
#include "TemplateableElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Class;
class Constraint;
class DataType;
class Interface;
class OperationTemplateParameter;
class Parameter;
class RedefinableElement;
class Type;

/// <summary>
/// Operation
/// An Operation is a BehavioralFeature of a Classifier that specifies the name,
/// type, parameters, and constraints for invoking an associated Behavior. An
/// Operation may invoke both the execution of method behaviors as well as other
/// behavioral responses. Operation specializes TemplateableElement in order to
/// support specification of template operations and bound operations. Operation
/// specializes ParameterableElement to specify that an operation can be exposed as
/// a formal template parameter, and provided as an actual parameter in a binding of
/// a template.
/// </summary>
class UMLMODEL_EXPORT Operation : public ParameterableElement, public BehavioralFeature, public TemplateableElement {

public: // Constructors and destructors
    explicit Operation(const QString& umlType="uml::Operation");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// isConsistentWith
    /// The query isConsistentWith() specifies, for any two Operations in a context in
    /// which redefinition is possible, whether redefinition would be consistent. A
    /// redefining operation is consistent with a redefined operation if
    /// it has
    /// the same number of owned parameters, and for each parameter the following
    /// holds:
    /// 
    /// - Direction, ordering and uniqueness are the same.
   
    /// /// - The corresponding types are covariant, contravariant or invariant.
    ///
    /// - The multiplicities are compatible, depending on the parameter direction.
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

    /// <summary>
    /// returnResults
    /// The query returnResult() returns the set containing the return parameter of the
    /// Operation if one exists, otherwise, it returns an empty set
    /// </summary>
    virtual shared_ptr<vector<Parameter>> returnResults() const;

public: // Properties
    /// <summary>
    /// bodyCondition getter
    /// An optional Constraint on the result values of an invocation of this Operation.
    /// </summary>
    shared_ptr<Constraint> bodyCondition() const;

    /// <summary>
    /// bodyCondition setter
    /// An optional Constraint on the result values of an invocation of this Operation.
    /// </summary>
    void setBodyCondition(shared_ptr<Constraint> value);

    /// <summary>
    /// class2 getter
    /// The Class that owns this operation, if any.
    /// </summary>
    shared_ptr<Class> class2() const;

    /// <summary>
    /// class2 setter
    /// The Class that owns this operation, if any.
    /// </summary>
    void setClass2(shared_ptr<Class> value);

    /// <summary>
    /// datatype getter
    /// The DataType that owns this Operation, if any.
    /// </summary>
    shared_ptr<DataType> datatype() const;

    /// <summary>
    /// datatype setter
    /// The DataType that owns this Operation, if any.
    /// </summary>
    void setDatatype(shared_ptr<DataType> value);

    /// <summary>
    /// interface2 getter
    /// The Interface that owns this Operation, if any.
    /// </summary>
    shared_ptr<Interface> interface2() const;

    /// <summary>
    /// interface2 setter
    /// The Interface that owns this Operation, if any.
    /// </summary>
    void setInterface2(shared_ptr<Interface> value);

    /// <summary>
    /// isOrdered getter
    /// Specifies whether the return parameter is ordered or not, if present.  This
    /// information is derived from the return result for this Operation.
    /// </summary>
    bool isOrdered() const;

    /// <summary>
    /// isOrdered setter
    /// Specifies whether the return parameter is ordered or not, if present.  This
    /// information is derived from the return result for this Operation.
    /// </summary>
    void setIsOrdered(bool value);

    /// <summary>
    /// isQuery getter
    /// Specifies whether an execution of the BehavioralFeature leaves the state of the
    /// system unchanged (isQuery=true) or whether side effects may occur
    /// (isQuery=false).
    /// </summary>
    bool isQuery() const;

    /// <summary>
    /// isQuery setter
    /// Specifies whether an execution of the BehavioralFeature leaves the state of the
    /// system unchanged (isQuery=true) or whether side effects may occur
    /// (isQuery=false).
    /// </summary>
    void setIsQuery(bool value);

    /// <summary>
    /// isUnique getter
    /// Specifies whether the return parameter is unique or not, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    bool isUnique() const;

    /// <summary>
    /// isUnique setter
    /// Specifies whether the return parameter is unique or not, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    void setIsUnique(bool value);

    /// <summary>
    /// lower getter
    /// Specifies the lower multiplicity of the return parameter, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    int lower() const;

    /// <summary>
    /// lower setter
    /// Specifies the lower multiplicity of the return parameter, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    void setLower(int value);

    /// <summary>
    /// ownedParameters getter
    /// The parameters owned by this Operation.
    /// </summary>
    vector<shared_ptr<Parameter>>& ownedParameters();

    /// <summary>
    /// postconditions getter
    /// An optional set of Constraints specifying the state of the system when the
    /// Operation is completed.
    /// </summary>
    vector<shared_ptr<Constraint>>& postconditions();

    /// <summary>
    /// preconditions getter
    /// An optional set of Constraints on the state of the system when the Operation is
    /// invoked.
    /// </summary>
    vector<shared_ptr<Constraint>>& preconditions();

    /// <summary>
    /// raisedExceptions getter
    /// The Types representing exceptions that may be raised during an invocation of
    /// this operation.
    /// </summary>
    vector<shared_ptr<Type>>& raisedExceptions();

    /// <summary>
    /// redefinedOperations getter
    /// The Operations that are redefined by this Operation.
    /// </summary>
    vector<shared_ptr<Operation>>& redefinedOperations();

    /// <summary>
    /// templateParameter getter
    /// The OperationTemplateParameter that exposes this element as a formal parameter.
    /// </summary>
    shared_ptr<OperationTemplateParameter> templateParameter() const;

    /// <summary>
    /// templateParameter setter
    /// The OperationTemplateParameter that exposes this element as a formal parameter.
    /// </summary>
    void setTemplateParameter(shared_ptr<OperationTemplateParameter> value);

    /// <summary>
    /// type getter
    /// The return type of the operation, if present. This information is derived from
    /// the return result for this Operation.
    /// </summary>
    shared_ptr<Type> type() const;

    /// <summary>
    /// type setter
    /// The return type of the operation, if present. This information is derived from
    /// the return result for this Operation.
    /// </summary>
    void setType(shared_ptr<Type> value);

    /// <summary>
    /// upper getter
    /// The upper multiplicity of the return parameter, if present. This information is
    /// derived from the return result for this Operation.
    /// </summary>
    int upper() const;

    /// <summary>
    /// upper setter
    /// The upper multiplicity of the return parameter, if present. This information is
    /// derived from the return result for this Operation.
    /// </summary>
    void setUpper(int value);

private: // Fields
    /// <summary>
    /// bodyCondition
    /// An optional Constraint on the result values of an invocation of this Operation.
    /// </summary>
    shared_ptr<Constraint> bodyCondition_;

    /// <summary>
    /// class2
    /// The Class that owns this operation, if any.
    /// </summary>
    shared_ptr<Class> class2_;

    /// <summary>
    /// datatype
    /// The DataType that owns this Operation, if any.
    /// </summary>
    shared_ptr<DataType> datatype_;

    /// <summary>
    /// interface2
    /// The Interface that owns this Operation, if any.
    /// </summary>
    shared_ptr<Interface> interface2_;

    /// <summary>
    /// isOrdered
    /// Specifies whether the return parameter is ordered or not, if present.  This
    /// information is derived from the return result for this Operation.
    /// </summary>
    const static bool isOrdered_default_;
    bool isOrdered_= isOrdered_default_;

    /// <summary>
    /// isQuery
    /// Specifies whether an execution of the BehavioralFeature leaves the state of the
    /// system unchanged (isQuery=true) or whether side effects may occur
    /// (isQuery=false).
    /// </summary>
    const static bool isQuery_default_;
    bool isQuery_= isQuery_default_;

    /// <summary>
    /// isUnique
    /// Specifies whether the return parameter is unique or not, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    const static bool isUnique_default_;
    bool isUnique_= isUnique_default_;

    /// <summary>
    /// lower
    /// Specifies the lower multiplicity of the return parameter, if present. This
    /// information is derived from the return result for this Operation.
    /// </summary>
    const static int lower_default_;
    int lower_= lower_default_;

    /// <summary>
    /// ownedParameters
    /// The parameters owned by this Operation.
    /// </summary>
    vector<shared_ptr<Parameter>> ownedParameters_;

    /// <summary>
    /// postconditions
    /// An optional set of Constraints specifying the state of the system when the
    /// Operation is completed.
    /// </summary>
    vector<shared_ptr<Constraint>> postconditions_;

    /// <summary>
    /// preconditions
    /// An optional set of Constraints on the state of the system when the Operation is
    /// invoked.
    /// </summary>
    vector<shared_ptr<Constraint>> preconditions_;

    /// <summary>
    /// raisedExceptions
    /// The Types representing exceptions that may be raised during an invocation of
    /// this operation.
    /// </summary>
    vector<shared_ptr<Type>> raisedExceptions_;

    /// <summary>
    /// redefinedOperations
    /// The Operations that are redefined by this Operation.
    /// </summary>
    vector<shared_ptr<Operation>> redefinedOperations_;

    /// <summary>
    /// templateParameter
    /// The OperationTemplateParameter that exposes this element as a formal parameter.
    /// </summary>
    shared_ptr<OperationTemplateParameter> templateParameter_;

    /// <summary>
    /// type
    /// The return type of the operation, if present. This information is derived from
    /// the return result for this Operation.
    /// </summary>
    shared_ptr<Type> type_;

    /// <summary>
    /// upper
    /// The upper multiplicity of the return parameter, if present. This information is
    /// derived from the return result for this Operation.
    /// </summary>
    const static int upper_default_;
    int upper_= upper_default_;

};

} // namespace uml
